package com.koudai.finance.utils.wxpay;

import com.github.wxpay.sdk.WXPayConstants;
import com.github.wxpay.sdk.WXPayUtil;
import com.google.common.collect.Maps;
import com.koudai.finance.utils.HttpClientUtils;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;

/**
 * @Description: 微信支付入口工具类
 * @Author: ls
 * @Date: 2020/08/10 10:37
 */
@Slf4j
public class WxPayUtils {

    /**
     * 微信js支付统一下单接口
     *
     * @param notifyUrl  回调地址
     * @param outTradeNo 商户订单号
     * @param totalFee   订单总金额
     * @param ip         IP
     * @param body       商品内容描述
     * @param openId     微信用户 OPENID
     * @throws Exception
     */
    public static Map<String, String> wxJsPay(String notifyUrl, String outTradeNo, String totalFee, String ip, String body, String openId) throws Exception {
        Map<String, String> mp = Maps.newHashMap();
        mp.put("appid", WxPayConfig.appId);
        // trade_type=NATIVE时(即扫码支付), 此参数必传. 此参数为二维码中包含的商品ID, 商户自行定义。
        mp.put("attach", body);
        // 商品描述
        mp.put("body", body);
        mp.put("mch_id", WxPayConfig.mchId);
        // 随机字符串
        mp.put("nonce_str", WXPayUtil.generateNonceStr());
        // 异步接收微信支付结果通知的回调地址, 通知url必须为外网可访问的url, 不能携带参数
        mp.put("notify_url", notifyUrl);
        // 商户订单号
        mp.put("out_trade_no", outTradeNo);
        // 终端IP
        mp.put("spbill_create_ip", ip);
        // 订单总金额, 单位为分
        mp.put("total_fee", totalFee);
        // 用户唯一标识
        mp.put("openid", openId);
        // 交易类型(JSAPI公众号支付/NATIVE扫码支付/APP支付)
        mp.put("trade_type", "JSAPI");
        String sign = WXPayUtil.generateSignature(mp, WxPayConfig.apiKey);
        mp.put("sign", sign);
        String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        String sb = WXPayUtil.mapToXml(mp);
        // 1、获取签名
        Map<String, String> firstMap = getCallResult(url, sb);
        // 2、二次验签
        Map<String, String> resultMap = Maps.newHashMap();
        if ("SUCCESS".equals(firstMap.get("return_code")) && firstMap.get("return_code").equals(firstMap.get("result_code"))) {
            long time = System.currentTimeMillis() / 1000;
            Map<String, String> secondMap = Maps.newHashMap();
            secondMap.put("appId", WxPayConfig.appId);
            secondMap.put("timeStamp", String.valueOf(time));
            secondMap.put("nonceStr", firstMap.get("nonce_str"));
            secondMap.put("package", "prepay_id=" + firstMap.get("prepay_id"));
            secondMap.put("signType", "MD5");
            String sign2 = WXPayUtil.generateSignature(secondMap, WxPayConfig.apiKey);
            // 3、封装返回结果
            resultMap.put("appId", WxPayConfig.appId);
            resultMap.put("timestamp", String.valueOf(time));
            resultMap.put("nonceStr", firstMap.get("nonce_str"));
            resultMap.put("package", "prepay_id=" + firstMap.get("prepay_id"));
            resultMap.put("sign", sign2);
        }
        return resultMap;
    }

    /**
     * 微信native支付统一下单接口
     *
     * @param notifyUrl  回调地址
     * @param outTradeNo 商户订单号
     * @param totalFee   订单总金额
     * @param ip         IP
     * @throws Exception
     */
    public static Map<String, String> wxNativePay(String notifyUrl, String outTradeNo, String totalFee, String ip, String body, String productId) throws Exception {
        Map<String, String> req = Maps.newHashMap();
        req.put("appid", WxPayConfig.appId); //公众号appid
        req.put("mch_id", WxPayConfig.mchId);  // 商户号
        req.put("nonce_str", WXPayUtil.generateNonceStr()); // 32位随机字符串
        req.put("body", body); // 商品描述
        req.put("out_trade_no", outTradeNo);   // 商户订单号
        req.put("product_id", productId);//商品id
        req.put("total_fee", totalFee);    // 标价金额(元)
        req.put("spbill_create_ip", ip);   // 终端IP
        req.put("notify_url", notifyUrl);  // 回调地址
        req.put("trade_type", "NATIVE");   // 交易类型
        req.put("sign", WXPayUtil.generateSignature(req, WxPayConfig.apiKey, WXPayConstants.SignType.MD5));  // 签名
        String xmlBody = WXPayUtil.generateSignedXml(req, WxPayConfig.apiKey);
        log.info("微信支付预下单请求参数xmlBody={}", WXPayUtil.xmlToMap(xmlBody));
        //发送 POST 请求 统一下单 API 并携带 xmlBody 内容,然后获得返回结果
        String result = HttpClientUtils.postReturnStr("https://api.mch.weixin.qq.com/pay/unifiedorder", xmlBody);
        return WXPayUtil.xmlToMap(result);
    }

    /**
     * @Description: 订单查询 out_trade_no    商户订单号
     * @Author: ls
     * @Date: 2020/08/10 13:48
     */
    public static Map<String, String> queryWxOrder(String outTradeNo) throws Exception {
        Map<String, String> paramMap = Maps.newHashMap();
        paramMap.put("appid", WxPayConfig.appId);
        paramMap.put("mch_id", WxPayConfig.mchId);
        paramMap.put("out_trade_no", outTradeNo);
        paramMap.put("nonce_str", WXPayUtil.generateNonceStr());
        paramMap.put("sign", WXPayUtil.generateSignature(paramMap, WxPayConfig.apiKey, WXPayConstants.SignType.MD5));
        String xmlBody = WXPayUtil.generateSignedXml(paramMap, WxPayConfig.apiKey);
        String url = "https://api.mch.weixin.qq.com/pay/orderquery";
        return getCallResult(url, xmlBody);
    }

    /**
     * @Description: 订单关闭
     * @Author: ls
     * @Date: 2020/08/10 13:50
     */
    public static Map<String, String> closeWxOrder(String out_trade_no) throws Exception {
        Map<String, String> mp = Maps.newHashMap();
        // 公众账号ID
        mp.put("appid", WxPayConfig.appId);
        // 商户号
        mp.put("mch_id", WxPayConfig.mchId);
        // 商户订单号 (2 S 1)
        mp.put("out_trade_no", out_trade_no);
        // 随机字符串
        mp.put("nonce_str", WXPayUtil.generateNonceStr());
        mp.put("sign", WXPayUtil.generateSignature(mp, WxPayConfig.apiKey, WXPayConstants.SignType.MD5));
        String xmlBody = WXPayUtil.generateSignedXml(mp, WxPayConfig.apiKey);
        String url = "https://api.mch.weixin.qq.com/pay/closeorder";
        return getCallResult(url, xmlBody);
    }

    /**
     * @Description: 查询退款 out_trade_no   商户订单号
     * @Author: ls
     * @Date: 2020/08/10 13:52
     */
    public Map<String, String> queryWxRefund(String out_trade_no) throws Exception {
        Map<String, String> mp = Maps.newHashMap();
        // 公众账号ID
        mp.put("appid", WxPayConfig.appId);
        // 商户号
        mp.put("mch_id", WxPayConfig.mchId);
        // 随机字符串
        mp.put("nonce_str", WXPayUtil.generateNonceStr());
        // mp.put("transaction_id", transaction_id);                            // 微信订单号 (4 S 1)
        // mp.put("out_refund_no", out_refund_no);                              // 商户退款单号 (4 S 1)
        // mp.put("refund_id", refund_id);                                      // 微信退款单号 (4 S 1)
        // 商户订单号 (4 S 1)
        mp.put("out_trade_no", out_trade_no);
        String sign = WXPayUtil.generateSignature(mp, WxPayConfig.apiKey);
        StringBuilder sb = new StringBuilder();
        sb.append("<xml>");
        sb.append("<appid>").append(mp.get("appid")).append("</appid>");
        sb.append("<mch_id><![CDATA[").append(mp.get("mch_id")).append("]]></mch_id>");
        sb.append("<nonce_str>").append(mp.get("nonce_str")).append("</nonce_str>");
        sb.append("<out_trade_no><![CDATA[").append(mp.get("out_trade_no")).append("]]></out_trade_no>");
        sb.append("<sign><![CDATA[").append(sign).append("]]></sign>");
        sb.append("</xml>");
        String url = "https://api.mch.weixin.qq.com/pay/refundquery";
        return getCallResult(url, sb.toString());
    }

    /**
     * @Description: 获取http调用结果
     * @Author: ls
     * @Date: 2020/08/10 14:00
     */
    private static Map<String, String> getCallResult(String url, String param) {
        Map<String, String> resultMap = Maps.newHashMap();
        try {
            String str = HttpClientUtils.postReturnStr(url, param);
            resultMap = WXPayUtil.xmlToMap(str);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultMap;
    }
}